package com.liao.ticket.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.liao.ticket.common.exception.BaseException;
import com.liao.ticket.common.exception.ErrorCode;
import com.liao.ticket.dao.mapper.OrderMapper;
import com.liao.ticket.dao.pojo.*;
import com.liao.ticket.service.*;
import com.liao.ticket.util.DateUtils;
import com.liao.ticket.util.PreferentialUtils;
import com.liao.ticket.util.UserThreadLocal;
import com.liao.ticket.vo.OrderVo;
import com.liao.ticket.vo.PassengerVo;
import com.liao.ticket.vo.Result;
import com.liao.ticket.vo.params.OrderParams;
import com.liao.ticket.vo.params.PageParams;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.sql.Wrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private PassengerService passengerService;

    @Autowired
    private SeatService seatService;

    @Autowired
    private FlightService flightService;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public Result findOrderById(Long id) {
        if(id == null){
            return Result.fail(ErrorCode.ORDER_PARAMS_ERROR);
        }
        LambdaQueryWrapper<Order> wrapper = wrapper();
        wrapper.eq(Order::getId, id);
        Order order = orderMapper.selectOne(wrapper);
        if(order == null){
            return Result.fail(ErrorCode.ORDER_NO_EXIT);
        }
        return Result.success(copy(order));
    }

    @Override
    public Result findOrderList(PageParams pageParams) {
        Page<Order> page = orderMapper.selectPage(new Page<>(pageParams.getPage(),pageParams.getPageSize()),wrapper());
        List<Order> orderList = page.getRecords();
        return Result.success(copy(orderList));
    }

    // 查询  指定日期当天 到 指定天数之前之间 的订单
    @Override
    public Result findOrderListByDate(OrderParams orderParams, PageParams pageParams) {
        String date = orderParams.getDate();
        Integer dayLen = orderParams.getDayLen();
        LambdaQueryWrapper<Order> wrapper = wrapper();
        wrapper.gt(Order::getDate, new Timestamp(DateUtils.toLongDay(date,1-dayLen)))
                .lt(Order::getDate, new Timestamp(DateUtils.toLongDay(orderParams.getDate(),1)));
        Page<Order> page = orderMapper.selectPage(new Page<>(pageParams.getPage(), pageParams.getPageSize()), wrapper);
        List<Order> orderList = page.getRecords();
        return Result.success(copy(orderList));
    }

    /**
     * *订单添加流程*
     * 1.检查所有id是否合法
     * 2.查询乘机人是否存在
     * 3.查询航班是否存在，若存在
     *   a.判断起飞时间据当前时间是否 > 2H
     *   b.判断当前状态是否为未起飞
     * 4.查询舱位是否存在，若存在则判断剩余票数是否 > 0
     * 5.获取用户信息,通过里程计算优惠
     * 6.将查询到的信息复制到订单中
     * 7.添加订单
     * 8.订单添加成功，修改用户信息，同步到数据库和redis
     * 9.返回下单成功提示
     */
    @Override
    public Result certainOrder(OrderParams orderParams, String token) {
        if(StringUtils.isBlank(token)){
            return Result.fail(ErrorCode.USER_SIGNING_FAIL);
        }
        User user = userService.selectById(UserThreadLocal.get().getId());
        if(user == null){
            return Result.fail(ErrorCode.USER_SIGNING_FAIL);
        }

        // 1.检查所有id是否合法
        Long flightId = orderParams.getFlightId();
        Long passengerId = orderParams.getPassengerId();
        Long seatId = orderParams.getSeatId();
        Long userId = user.getId();
        if (flightId == null || passengerId == null || seatId == null || userId == null) {
            return Result.fail(ErrorCode.ORDER_ADD_PARAMS_ERROR);
        }

        // 2.查询乘机人是否存在
        Passenger passenger = passengerService.findOneByIdAndUid(passengerId);
        if(passenger == null){
            return Result.fail(ErrorCode.USER_PASSENGER_NO_EXIT);
        }

        // 3.查询航班是否存在，若存在
        Flight flight =  flightService.findOneById(flightId);
        if(flight == null){
            return Result.fail(ErrorCode.ORDER_ADD_FLIGHT_NO_EXIT_ERROR);
        }
        // a.判断起飞时间据当前时间是否 > 2H  ；b.判断当前状态是否为未起飞
        if((flight.getType() != 0 || flight.getFlyTime().getTime() < (System.currentTimeMillis()+(2 * 60 * 60 * 1000)))){
            return Result.fail(ErrorCode.ORDER_ADD_OVERTIME_ERROR);
        }

        // 4.查询舱位是否存在，若存在则判断剩余票数是否 > 0
        Seat seat = seatService.selectOneByIdAndFid(seatId, flightId);
        if (seat == null) {
            return Result.fail(ErrorCode.ORDER_ADD_NO_SEAT_ERROR);
        }
        if(seat.getNum() <= 0 ){
            return Result.fail(ErrorCode.ORDER_ADD_NO_SEAT_NUM_ERROR);
        }

        /*
        * 5.获取用户信息,通过里程计算优惠:
        * 1.黄金vip
        *   里程数 > 10000 , 优惠 0.98
        * 2.白金vip
        *   里程数 > 20000 , 优惠 0.95 , 5kg托运
        * 3.钻石vip
        *   里程数 > 100000 , 优惠 0.90 ， 10kg托运
        * */
        BigDecimal price = PreferentialUtils.getPrice(user.getMileage(), seat.getPrice());

        // 6.将查询到的信息复制到订单中
        Order order = new Order();
        order.setDate(new Timestamp(System.currentTimeMillis()));
        order.setAirportFlyName(flight.getAirportFlyName());
        order.setAirportToName(flight.getAirportToName());
        order.setFlightId(flightId);
        order.setFlightName(flight.getName());
        order.setFlyPlace(flight.getFlyPlace());
        order.setToPlace(flight.getToPlace());
        order.setFlyTime(flight.getFlyTime());
        order.setToTime(flight.getToTime());
        order.setFlightType(flight.getType());
        order.setMileage(flight.getMileage());
        order.setPassengerId(passengerId);
        order.setPrice(price);
        order.setTicket(seat.getType());
        order.setType(0);
        order.setName(passenger.getName());
        order.setPhone(passenger.getPhone());
        order.setIdcard(passenger.getIdcard());

        order.setUserId(userId);

        // 7.添加订单
        int insert = orderMapper.insert(order);
        if(insert <= 0 ){
            throw new BaseException(ErrorCode.ORDER_ADD_ERROR);
        }

        // 8.订单添加成功，修改用户信息，同步到数据库和redis
        Integer mileage = user.getMileage() + flight.getMileage();
        price = price.add(user.getConsume());
        user.setMileage(mileage);
        user.setConsume(price);
        Integer update = userService.updateMileageAndConsumeById(user);
        if (update <= 0) {
            throw new BaseException(ErrorCode.USER_CONSUMER_SQL_ERROR);
        }
        redisTemplate.opsForValue().set("TOKEN_" + token, JSON.toJSONString(user), 1, TimeUnit.DAYS);

        // 9.返回下单成功提示
        return Result.success("订票成功！");
    }

    /**
     * 取消订单
     * 1.检查参数是否合法
     * 2.查询订单是否存在
     * 3.判断订单是否符合取消条件
     * 4.重新查询用户信息
     * 5.更新订单状态为 -1
     * 6.更新用户信息
     * 7.同步redis
     * 8.返回订单取消成功提示
     * @param id
     * @param token
     * @return
     */
    @Override
    public Result cancelOrder(Long id,String token) {
        if (id == null || token == null) {
            return Result.fail(ErrorCode.ORDER_PARAMS_ERROR);
        }
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getId, id).eq(Order::getUserId,UserThreadLocal.get().getId());
        Order order = orderMapper.selectOne(wrapper);
        if (order == null) {
            return Result.fail(ErrorCode.ORDER_NO_EXIT);
        }
        // 订单状态不为0 或者 据起飞时间小于2小时 或者 下单超过12个小时 订单无法取消
        if (order.getType() != 0) {
            return Result.fail(ErrorCode.ORDER_CANCEL_STATE_ERROR);
        }
        if(order.getFlyTime().getTime() - System.currentTimeMillis() < 2 * 60 * 60 * 1000 ){
            return Result.fail(ErrorCode.ORDER_CANCEL_WILL_FLY);
        }
        if(System.currentTimeMillis() - order.getDate().getTime() > 4 * 60 * 60 * 1000){
            return Result.fail(ErrorCode.ORDER_CANCEL_OVERTIME);
        }
        User user = userService.selectById(UserThreadLocal.get().getId());
        if (user == null) {
            return Result.fail(ErrorCode.USER_NO_EXIT);
        }
        // 订单 取消 状态设为 20
        order.setType(20);
        int oi = orderMapper.updateById(order);
        if (oi <= 0) {
            throw new BaseException(ErrorCode.ORDER_UPDATE_ERROR);
        }
        BigDecimal consume = user.getConsume().subtract(order.getPrice());
        Integer mileage = user.getMileage()-order.getMileage();
        user.setConsume(consume);
        user.setMileage(mileage);
        Integer ui = userService.updateMileageAndConsumeById(user);
        if (ui <= 0) {
            throw new BaseException(ErrorCode.ORDER_UPDATE_ERROR);
        }
        redisTemplate.opsForValue().set("TOKEN_" + token, JSON.toJSONString(user), 1, TimeUnit.DAYS);
        return Result.success("订单已取消！");
    }

    @Override
    public Result updatePhoneById(OrderParams orderParams) {
        Long id = orderParams.getId();
        String phone = orderParams.getPhone();
        if (id == null || StringUtils.isBlank(phone)) {
            return Result.fail(ErrorCode.ORDER_PARAMS_ERROR);
        }
        Order order = new Order();
        order.setPhone(phone);

        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getType,0).eq(Order::getId,id).eq(Order::getUserId,UserThreadLocal.get().getId());
        int i = orderMapper.update(order,wrapper);
        if (i <= 0) {
            return Result.fail(ErrorCode.ORDER_UPDATE_ERROR);
        }
        return Result.success("订单手机号已修改！");
    }

    private LambdaQueryWrapper<Order> wrapper(){
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Order::getUserId,UserThreadLocal.get().getId());
        return wrapper;
    }

    private OrderVo copy(Order order) {
        PassengerVo passengerVo = passengerService.selectOneById(order.getPassengerId());
        OrderVo orderVo = new OrderVo();
        BeanUtils.copyProperties(order, orderVo);
        orderVo.setPassengerVo(passengerVo);
        return orderVo;
    }

    private List<OrderVo> copy(List<Order> orderList) {
        List<OrderVo> orderVoList = new ArrayList<>();
        orderList.forEach(i -> orderVoList.add(copy(i)));
        return orderVoList;
    }
}
